<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>闭包</title>
</head>

<body>
  <button>按钮1</button>
  <button>按钮2</button>
  <button>按钮3</button>
  <!-- 
    1、如何产生闭包
      * 当一个嵌套的内部（子）函数引用了前台的外部（父）函数的变量时，就产生闭包
    2、闭包到底是什么
      * 函数的作用域是在函数定义时决定的
      * 函数的执行依赖于函数自身变量及自身所在作用域链中的位置
      * 函数保留自身变量和自身所在作用域链中位置的现象，在计算机科学中呗成为闭包。
      * 闭包在定义时就决定了，与函数调用无关
      * 使用chrom调试器查看
      * 理解一：闭包是嵌套的内部函数（觉得大部分人）
      * 理解二：包含被引用变量（函数）的对象（很少数人）
      * 注意：闭包存在于嵌套的内部函数中
    3、产生闭包的条件
      * 函数嵌套
      * 内部函数引用了外部函数的数据（变量/函数）
   -->
  <script>
    var btnArr = document.getElementsByTagName('button')
    // 错误例子
    // for (var i = 0; arrLnegth = btnArr.length, i < arrLnegth; i++) {
    //   var btn = btnArr[i]
    //   btn.addEventListener('click',function(){
    //     alert(i+1)
    //   })
    // }
    // 解决方式1
    // for (var i = 0; arrLnegth = btnArr.length, i < arrLnegth; i++) {
    //   var btn = btnArr[i]
    //   btn.index=i
    //   btn.addEventListener('click',function(){
    //     alert(this.index+1)
    //   })
    // }
    // 解决方式2：闭包解决
    for (var i = 0; arrLnegth = btnArr.length, i < arrLnegth; i++) {
      (function (i) {
        var btn = btnArr[i]
        btn.addEventListener('click', function () {
          alert(i + 1)
        })
      })(i)
    }
  </script>
  <!-- 
    1、常见闭包情况
      * 将函数作为另一个函数的返回值
      * 将函数作为实参传递给另一个函数调用
   -->
  <!-- 
    作用
      1、使用函数内部的变量在函数执行完后，仍然存活在内存中（演唱了局部变量的声明周期）
      2、让函数外部可以操作（读写）函数内部的数据（变量或函数）
    -->
  <!-- 
    缺点
      * 函数执行完成后，函数内的局部变量没有释放，占用内存时间会变长
      * 容易造成内存溢出
    解决
      * 能不用闭包就不用
      * 及时释放（置为null）
   -->
  <!-- 
    闭包应用2：定义JS模块
      * 具有特定功能的js文件
      * 将所有的数据和功能都封装在一个函数内部（私有的）
      * 只向外暴露一个单包含n个方法的对象或函数
      * 模块的使用者，只需要通过模块暴露的对象调用方法来实现对应的功能
   -->
  <!-- 
    闭包的声明周期
      1、产生：在嵌套内部函数定义执行完时就产生了（不是在调用时）
      2、死亡：在嵌套的内部函数称为垃圾对象时
    -->
  <script>
    //  将函数作为另一个函数的返回值
    function fn1() {
      var a = 3
      function fn2() {
        a++
        console.log(a)
      }
      return fn2
    }
    var f = fn1()
    f()//4
    f()//5
    f = null//闭包死亡
    // 将函数作为实参传递给另一个函数调用
    function showDelay(msg, time) {
      setTimeout(function () {
        console.log(msg)
      }, time)
    }
    showDelay('info', 1000)
  </script>
  <!-- 题 -->
  <script>
    function fun(n,o){//0,undefined
      console.log(o)
      return {
        fun:function(m){//1
          return fun(m,n)//1,0
        }
      }
    }
    console.log('=====闭包题目=====')
    // 思路：闭包是否产生，产生后是否有用
    var a = fun(0);a.fun(1);a.fun(2);a.fun(3);//undefined,0,0,0
    var b = fun(0).fun(1).fun(2).fun(3);//undefined,0,1,2
    var c = fun(0).fun(1);
    c.fun(2);
    c.fun(3);//undefined,0,1,1
  </script>
</body>

</html>